/*
 * Copyright (c) 2022 iSoftStone Information Technology (Group) Co.,Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.isoftstone.simplepiano.utils;

import com.isoftstone.simplepiano.AudioPlaybackCapabilityInterfaceProxy;
import com.isoftstone.simplepiano.ResourceTable;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.ability.fraction.Fraction;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.element.PixelMapElement;
import ohos.app.Context;
import ohos.bundle.ElementName;
import ohos.global.resource.Resource;
import ohos.multimodalinput.event.TouchEvent;
import ohos.rpc.IRemoteObject;
import ohos.rpc.RemoteException;

import java.util.HashMap;

public class RangeSelectionUtils {

    //钢琴音频
    public final int PLAY_AUDIO_MSG = 100;
    private Button[] buttons;
    private Fraction mFraction;
    private Context mContext;

    //选择结果
    private String mSelectionResults;

    AudioPlaybackCapabilityInterfaceProxy PlayerAudioInterfaceProxy = null;
    private final IAbilityConnection AudioAbilityConnection = new IAbilityConnection() {
        @Override
        public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
            PlayerAudioInterfaceProxy = new AudioPlaybackCapabilityInterfaceProxy(iRemoteObject);
        }

        @Override
        public void onAbilityDisconnectDone(ElementName elementName, int i) {
            PlayerAudioInterfaceProxy = null;
        }
    };

    public void setFraction(Fraction fraction) {
        this.mFraction = fraction;
    }

    public void setContext(Context context) {
        this.mContext = context;
    }

    public void initButton(String selectResults) {
        mSelectionResults = selectResults;
        switch (selectResults) {
            case ConstantUtils.ONE_FRACTION:
                getOneLayout();
                break;
            case ConstantUtils.TWO_FRACTION:
                getGeneralKey(ResourceTable.Id_two_PianoC, ResourceTable.Id_two_PianoD, ResourceTable.Id_two_PianoE, ResourceTable.Id_two_PianoF, ResourceTable.Id_two_PianoG, ResourceTable.Id_two_PianoA, ResourceTable.Id_two_PianoB, ResourceTable.Id_two_PianoCm, ResourceTable.Id_two_PianoDm, ResourceTable.Id_two_PianoFm, ResourceTable.Id_two_PianoGm, ResourceTable.Id_two_PianoAm);
                break;
            case ConstantUtils.THREE_FRACTION:
                getGeneralKey(ResourceTable.Id_three_Pianoc, ResourceTable.Id_three_Pianod, ResourceTable.Id_three_Pianoe, ResourceTable.Id_three_Pianof, ResourceTable.Id_three_Pianog, ResourceTable.Id_three_Pianoa, ResourceTable.Id_three_Pianob, ResourceTable.Id_three_Pianocm, ResourceTable.Id_three_Pianodm, ResourceTable.Id_three_Pianofm, ResourceTable.Id_three_Pianogm, ResourceTable.Id_three_Pianoam);
                break;
            case ConstantUtils.FOUR_FRACTION:
                getGeneralKey(ResourceTable.Id_four_Pianoc1, ResourceTable.Id_four_Pianod1, ResourceTable.Id_four_Pianoe1, ResourceTable.Id_four_Pianof1, ResourceTable.Id_four_Pianog1, ResourceTable.Id_four_Pianoa1, ResourceTable.Id_four_Pianob1, ResourceTable.Id_four_Pianoc1m, ResourceTable.Id_four_Pianod1m, ResourceTable.Id_four_Pianof1m, ResourceTable.Id_four_Pianog1m, ResourceTable.Id_four_Pianoa1m);
                break;
            case ConstantUtils.FIVE_FRACTION:
                getGeneralKey(ResourceTable.Id_five_Pianoc2, ResourceTable.Id_five_Pianod2, ResourceTable.Id_five_Pianoe2, ResourceTable.Id_five_Pianof2, ResourceTable.Id_five_Pianog2, ResourceTable.Id_five_Pianoa2, ResourceTable.Id_five_Pianob2, ResourceTable.Id_five_Pianoc2m, ResourceTable.Id_five_Pianod2m, ResourceTable.Id_five_Pianof2m, ResourceTable.Id_five_Pianog2m, ResourceTable.Id_five_Pianoa2m);
                break;
            case ConstantUtils.SIX_FRACTION:
                getGeneralKey(ResourceTable.Id_six_Pianoc3, ResourceTable.Id_six_Pianod3, ResourceTable.Id_six_Pianoe3, ResourceTable.Id_six_Pianof3, ResourceTable.Id_six_Pianog3, ResourceTable.Id_six_Pianoa3, ResourceTable.Id_six_Pianob3, ResourceTable.Id_six_Pianoc3m, ResourceTable.Id_six_Pianod3m, ResourceTable.Id_six_Pianof3m, ResourceTable.Id_six_Pianog3m, ResourceTable.Id_six_Pianoa3m);
                break;
            case ConstantUtils.SEVEN_FRACTION:
                getSevenKey();
                break;
        }

    }

    //大字二  一组按键
    private void getOneLayout() {
        int[] buttonOneId = new int[15];
        buttonOneId[0] = ResourceTable.Id_one_PianoA2;
        buttonOneId[1] = ResourceTable.Id_one_PianoB2;

        buttonOneId[2] = ResourceTable.Id_one_PianoC1;
        buttonOneId[3] = ResourceTable.Id_one_PianoD1;
        buttonOneId[4] = ResourceTable.Id_one_PianoE1;
        buttonOneId[5] = ResourceTable.Id_one_PianoF1;
        buttonOneId[6] = ResourceTable.Id_one_PianoG1;
        buttonOneId[7] = ResourceTable.Id_one_PianoA1;
        buttonOneId[8] = ResourceTable.Id_one_PianoB1;

        buttonOneId[9] = ResourceTable.Id_one_PianoA2m;

        buttonOneId[10] = ResourceTable.Id_one_PianoC1m;
        buttonOneId[11] = ResourceTable.Id_one_PianoD1m;
        buttonOneId[12] = ResourceTable.Id_one_PianoF1m;
        buttonOneId[13] = ResourceTable.Id_one_PianoG1m;
        buttonOneId[14] = ResourceTable.Id_one_PianoA1m;

        buttons = new Button[15];
        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = (Button) mFraction.getFractionAbility().findComponentById(buttonOneId[i]);
        }
    }

    //大字组,小字组,小字一,二,三组按键
    private void getGeneralKey(int key1, int key2, int key3, int key4, int key5, int key6, int key7, int key8, int key9, int key10, int key11, int key12) {
        int[] buttonTwoId = new int[12];
        buttonTwoId[0] = key1;
        buttonTwoId[1] = key2;
        buttonTwoId[2] = key3;
        buttonTwoId[3] = key4;
        buttonTwoId[4] = key5;
        buttonTwoId[5] = key6;
        buttonTwoId[6] = key7;

        buttonTwoId[7] = key8;
        buttonTwoId[8] = key9;
        buttonTwoId[9] = key10;
        buttonTwoId[10] = key11;
        buttonTwoId[11] = key12;

        buttons = new Button[12];
        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = (Button) mFraction.getFractionAbility().findComponentById(buttonTwoId[i]);
        }
    }

    //小字四  五组按键
    private void getSevenKey() {
        int[] buttonSevenId = new int[13];
        buttonSevenId[0] = ResourceTable.Id_seven_Pianoc4;
        buttonSevenId[1] = ResourceTable.Id_seven_Pianod4;
        buttonSevenId[2] = ResourceTable.Id_seven_Pianoe4;
        buttonSevenId[3] = ResourceTable.Id_seven_Pianof4;
        buttonSevenId[4] = ResourceTable.Id_seven_Pianog4;
        buttonSevenId[5] = ResourceTable.Id_seven_Pianoa4;
        buttonSevenId[6] = ResourceTable.Id_seven_Pianob4;

        buttonSevenId[7] = ResourceTable.Id_seven_Pianoc5;

        buttonSevenId[8] = ResourceTable.Id_seven_Pianoc4m;
        buttonSevenId[9] = ResourceTable.Id_seven_Pianod4m;
        buttonSevenId[10] = ResourceTable.Id_seven_Pianof4m;
        buttonSevenId[11] = ResourceTable.Id_seven_Pianog4m;
        buttonSevenId[12] = ResourceTable.Id_seven_Pianoa4m;

        buttons = new Button[13];
        for (int i = 0; i < buttons.length; i++) {
            buttons[i] = (Button) mFraction.getFractionAbility().findComponentById(buttonSevenId[i]);
        }
    }

    private final Component.TouchEventListener touchEventListener = (component, touchEvent) -> {
        int pointerIndex = touchEvent.getIndex();
        int pointerId = touchEvent.getPointerId(pointerIndex);
        float x = touchEvent.getPointerPosition(pointerIndex).getX();
        float y = touchEvent.getPointerPosition(pointerIndex).getY();
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
            case TouchEvent.OTHER_POINT_DOWN:
                onFingerPress(pointerId, x, y);
                break;
            case TouchEvent.OTHER_POINT_UP:
            case TouchEvent.PRIMARY_POINT_UP:
                onFingerLift(pointerId, x, y);
                break;
            case TouchEvent.POINT_MOVE:
                int pointCount = touchEvent.getPointerCount();
                for (int i = 0; i < pointCount; i++) {
                    onFingerSlide(touchEvent.getPointerId(i), touchEvent.getPointerPosition(i).getX(), touchEvent.getPointerPosition(i).getY());
                }
                break;
            case TouchEvent.CANCEL:
                onAllFingersLift();
                break;
        }
        return true;
    };

    public Component.TouchEventListener getTouchEventListener() {
        return touchEventListener;
    }


    //处理触摸处理相关
    private final HashMap<Integer, Integer> keyMap = new HashMap<>();

    //手指按下
    private void onFingerPress(int index, float x, float y) {
        int key = isInScale(x, y, mContext);
        if (key != -1) {
            fireKeyPress(key);
            this.keyMap.put(index, key);
        }
    }

    //手指松开
    private void onFingerLift(int index, float x, float y) {
        if (this.keyMap.get(index) != null) {
            int key = this.keyMap.get(index);
            //按键松开
            fireKeyLift(key);
            this.keyMap.remove(index);
        } else {
            int newKey = isInScale(x, y, mContext);
            //按键松开
            if (newKey != -1) {
                fireKeyLift(newKey);
            }
        }
    }

    //手指移动
    private void onFingerSlide(int index, float x, float y) {
        //当前按键key
        int currentKey = isInScale(x, y, mContext);
        if (currentKey != -1) {
            if (this.keyMap.get(index) != null) {
                int newKey = this.keyMap.get(index);
                if ((currentKey >= 0) && (currentKey != newKey)) {
                    fireKeyPress(currentKey);
                    fireKeyLift(newKey);
                    this.keyMap.put(index, currentKey);
                }
            }
        }
    }

    private void onAllFingersLift() {
        for (Integer integer : this.keyMap.values()) {
            fireKeyLift(integer);
        }
        this.keyMap.clear();
    }

    //按键松开
    private void fireKeyLift(int key) {
        switch (mSelectionResults) {
            case ConstantUtils.ONE_FRACTION:
                keyRecovery(key, 9, ResourceTable.Media_black_key, ResourceTable.Media_white_key);
                break;
            case ConstantUtils.SEVEN_FRACTION:
                keyRecovery(key, 8, ResourceTable.Media_black_key, ResourceTable.Media_white_key);
                break;
            default:
                keyRecovery(key, 7, ResourceTable.Media_black_key, ResourceTable.Media_white_key);
        }

    }

    private void keyRecovery(int key, int i, int p, int p2) {
        if (key >= i) {
            PixelMapElement blackElement = getElement(p);
            buttons[key].setBackground(blackElement);
        } else {
            PixelMapElement whiteElement = getElement(p2);
            buttons[key].setBackground(whiteElement);
        }
    }


    //按键按下
    private void fireKeyPress(int key) {
        //播放音频
        PlayAudio(key);
        switch (mSelectionResults) {
            case ConstantUtils.ONE_FRACTION:
                keyRecovery(key, 9, ResourceTable.Media_black_key_press, ResourceTable.Media_white_key_press);
                break;
            case ConstantUtils.TWO_FRACTION:
            case ConstantUtils.THREE_FRACTION:
            case ConstantUtils.FOUR_FRACTION:
            case ConstantUtils.FIVE_FRACTION:
            case ConstantUtils.SIX_FRACTION:
                keyRecovery(key, 7, ResourceTable.Media_black_key_press, ResourceTable.Media_white_key_press);
                break;
            case ConstantUtils.SEVEN_FRACTION:
                keyRecovery(key, 8, ResourceTable.Media_black_key_press, ResourceTable.Media_white_key_press);
                break;
            default:
                break;
        }
    }

    private PixelMapElement getElement(int p) {
        Resource whiteResource = null;
        try {
            whiteResource = mFraction.getResourceManager().getResource(p);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new PixelMapElement(whiteResource);
    }

    private void PlayAudio(int indexPressedKey) {
        switch (mSelectionResults) {
            case ConstantUtils.ONE_FRACTION:
                sendCommand(indexPressedKey, 0);
                break;
            case ConstantUtils.TWO_FRACTION:
                sendCommand(indexPressedKey, 1);
                break;
            case ConstantUtils.THREE_FRACTION:
                sendCommand(indexPressedKey, 2);
                break;
            case ConstantUtils.FOUR_FRACTION:
                sendCommand(indexPressedKey, 3);
                break;
            case ConstantUtils.FIVE_FRACTION:
                sendCommand(indexPressedKey, 4);
                break;
            case ConstantUtils.SIX_FRACTION:
                sendCommand(indexPressedKey, 5);
                break;
            case ConstantUtils.SEVEN_FRACTION:
                sendCommand(indexPressedKey, 6);
                break;
        }

    }

    private void sendCommand(int indexPressedKey, int i) {
        try {
            PlayerAudioInterfaceProxy.sendCommand(PLAY_AUDIO_MSG, indexPressedKey, i);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    //判断某个点是否在某个按钮的范围内
    private int isInScale(float x, float y, Context context) {
        int i = -1;
        int windowWidth = WindowUtil.getWindowWidth(context);
        int width = windowWidth / 7;
        switch (mSelectionResults) {
            case ConstantUtils.ONE_FRACTION:
                width = windowWidth / 9;
                i = getOtherKey(x, y, i, width);
                break;
            case ConstantUtils.TWO_FRACTION:
            case ConstantUtils.THREE_FRACTION:
            case ConstantUtils.FOUR_FRACTION:
            case ConstantUtils.FIVE_FRACTION:
            case ConstantUtils.SIX_FRACTION:
                i = getKey(x, y, i, width, 0.5, 1.2, 7, 1.8, 2.55, 8, 3.5, 4.2, 9, 4.65, 5.35, 10, 5.8, 6.55, 11);
                break;
            case ConstantUtils.SEVEN_FRACTION:
                width = windowWidth / 8;
                i = getKey(x, y, i, width, 0.55, 1.3, 8, 1.65, 2.4, 9, 3.4, 4.15, 10, 4.5, 5.25, 11, 5.6, 6.35, 12);
                break;
            default:
                break;
        }
        return i;
    }
    //大字组,小字组,小字一,二,三,四组
    private int getKey(float x, float y, int i, int width, double v, double v2, int i2, double v3, double v4, int i3, double v5, double v6, int i4, double v7, double v8, int i5, double v9, double v10, int i6) {
        if (y > 500) {
            i = (int) (x / width);
        } else {
            if (x > width * v && x < width * v2) {
                i = i2;
            } else if (x > width * v3 && x < width * v4) {
                i = i3;
            } else if (x > width * v5 && x < width * v6) {
                i = i4;
            } else if (x > width * v7 && x < width * v8) {
                i = i5;
            } else if (x > width * v9 && x < width * v10) {
                i = i6;
            }
        }
        return i;
    }
    //大字二,一组
    private int getOtherKey(float x, float y, int i, int width) {
        if (y > 500) {
            i = (int) (x / width);
        } else {
            if (x > width * 0.8 && x < width * 1.5) {
                i = 9;
            } else if (x > width * 2.55 && x < width * 3.3) {
                i = 10;
            } else if (x > width * 3.7 && x < width * 4.4) {
                i = 11;
            } else if (x > width * 5.5 && x < width * 6.2) {
                i = 12;
            } else if (x > width * 6.6 && x < width * 7.35) {
                i = 13;
            } else if (x > width * 7.75 && x < width * 8.5) {
                i = 14;
            }
        }
        return i;
    }

    public void startLocalAudioPlay(Context context) {
        Intent localIntent = new Intent();
        Operation localOperation = new Intent.OperationBuilder()
                .withBundleName(context.getBundleName())
                .withAbilityName(ConstantUtils.AUDIO_ABILITY_MAIN)
                .withFlags(Intent.FLAG_START_FOREGROUND_ABILITY)
                .build();
        localIntent.setOperation(localOperation);
        context.getAbilityPackageContext().connectAbility(localIntent, AudioAbilityConnection);
    }
}
